package org.ala.tiktools.rpc.kcp.netty.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;

import org.ala.tiktools.rpc.kcp.config.RpcKcpConfigInfo;
import org.ala.tiktools.rpc.kcp.netty.IKcpChannelConfig;
import org.ala.tiktools.rpc.kcp.netty.IKcpServerChildChannel;
import org.ala.tiktools.rpc.kcp.netty.NettyKcp;
import org.ala.tiktools.rpc.kcp.netty.server.config.DefaultKcpServerChildChannelConfig;
import org.ala.tiktools.tools.TimestampTools;

import io.netty.buffer.ByteBuf;
import io.netty.channel.AbstractChannel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoop;

/**
 * 服务端持有的客户端连接（虚拟连接，底层并不实际对应某个socket套接字。udp也没长连socket给你绑定）
 * <p>  在boss线程做所有事情
 *
 * @author ala
 * @date 2025-04-14 15:41
 */
public class KcpServerChildChannel extends AbstractChannel implements IKcpServerChildChannel {
    /**
     *
     */
    protected NettyKcp nkcp;
    /**
     *
     */
    protected InetSocketAddress remoteAddress;
    /**
     *  flush标记
     */
    private boolean flushPending;
    /**
     *
     */
    private DefaultKcpServerChildChannelConfig config;
    /**
     *
     */
    private static final ChannelMetadata METADATA = new ChannelMetadata(false);
    /**
     *
     * @param parent
     * @param kcp
     * @param remoteAddress
     */
    public KcpServerChildChannel(Channel parent, NettyKcp nkcp, InetSocketAddress remoteAddress) {
        super(parent);
        this.config = new DefaultKcpServerChildChannelConfig(this, nkcp);
        this.nkcp = nkcp;
        nkcp.channel(this);
        nkcp.setFastFlush(RpcKcpConfigInfo.INSTANCE.isIkcpFastFlush());
        this.remoteAddress = remoteAddress;
    }


    @Override
    public KcpServerChannel parent() {
        return (KcpServerChannel) super.parent();
    }


    /**
     *  eventLoop注册成功回调
     *  <p> ChannelPipeline.handler里有一个，不过那是面相应用层的。channel层用起来不方便
     */
    public void afterEventLoopRegister() {
    }


    /**
     * 检测刷新时间戳
     */
    public int kcpCheck(int current) {
        return nkcp.check(current);
    }
    /**
     *  设置下轮flush时间戳
     */
    public void kcpTsUpdate(int tsUp) {
    	nkcp.setTsUpdate(tsUp);
    }
    /**
     *  执行input
     */
    public void kcpInput(ByteBuf buf) throws IOException {
    	nkcp.input(buf);
    }
    /**
     * 判断kcp是否可以发送数据
     */
    public boolean kcpCanSend() {
        return nkcp.canSend(!flushPending);
    }
    /**
     *  rcvQue 中第一个消息字节数
     *  @return -1:queue为空<br/>
     *          -2:queue中还么有收到一个完整消息<br/>
     *          >0 一个完整消息的字节数
     */
    public int peekSize() {
        return nkcp.peekSize();
    }
    /**
     *  将rcvQue中的数据，读进recvBuf
     *  <p> 只读第一个完整消息
     */
    public void kcpReceive(ByteBuf recvBuf) {
    	nkcp.receive(recvBuf);
    }
    /**
     *  将rcvQue中的数据，读进bufList
     *  <p> 只读第一个完整消息
     */
    public void kcpReceive(List<ByteBuf> bufList) {
    	nkcp.receive(bufList);
    }
    /**
     *  是否可读
     */
    public boolean kcpCanRecv() {
        return nkcp.canRecv();
    }
    /**
     *  发送数据
     */
    public boolean kcpSend(ByteBuf buf) throws IOException {
        if (nkcp.canSend(true)) {
        	nkcp.send(buf);
            return true;
        }
        return false;
    }


    @Override
    public int conv() { return nkcp.getConv(); }
    @Override
    public KcpServerChildChannel conv(int conv) { nkcp.setConv(conv); return this; }
    @Override
    public KcpServerChildUnsafe unsafe() { return (KcpServerChildUnsafe) super.unsafe(); }
    @Override
    public boolean isActive() { return isOpen(); }
    @Override
    public boolean isOpen() { return nkcp.isActive(); }
    @Override
    public ChannelMetadata metadata() { return METADATA; }
    @Override
    public IKcpChannelConfig config() { return config; }
    @Override
    protected AbstractUnsafe newUnsafe() { return new KcpServerChildUnsafe(); }
    @Override
    protected boolean isCompatible(EventLoop loop) {  return loop instanceof NioEventLoop; }
    @Override
    protected SocketAddress localAddress0() { return parent().localAddress0(); }
    @Override
    public InetSocketAddress localAddress() { return (InetSocketAddress) super.localAddress(); }
    @Override
    public InetSocketAddress remoteAddress() { return remoteAddress; }
    @Override
    protected InetSocketAddress remoteAddress0() { return remoteAddress; }
    @Override
    protected void doBind(SocketAddress localAddress) throws Exception { throw new UnsupportedOperationException(); }
    @Override
    protected void doDisconnect() throws Exception { throw new UnsupportedOperationException(); }
    @Override
    protected void doBeginRead() throws Exception {}


    /**
     * 关闭事件
     */
    @Override
    protected void doClose() throws Exception {
        parent().doCloseChildChannel(this);
    }


    /**
     * 吧待发送的数据写入sndQue，等待flush()真实发送出去
     * <p>  flush在KcpServerChannel.WriterRunner()中
     */
    @Override
    protected void doWrite(ChannelOutboundBuffer in) throws Exception {
        boolean sent = false;
        //  从in中不断取数，放入sndQue中。等下个flush轮中再真实发送
        while (true) {
            Object o = in.current();
            if (o == null) {
                flushPending = false;
                break;
            }
            boolean done = false;
            if (kcpSend((ByteBuf) o)) {
                done = true;
                sent = true;
            }
            if (done) {
                in.remove();
            } else {
                flushPending = false;
                break;
            }
        }
        //  如果确实取到了数据，放入sndQue，判断是否快速刷新
        if (sent) {
            //  如果是快速刷新，当场刷一遍
            if (nkcp.isFastFlush()) {
                parent().updateChildKcp(this);
            }
            //  如果不是，设置下次刷新时间点
            else {
            	nkcp.setTsUpdate(TimestampTools.milliSeconds32());
            }
        }
    }


    public InetSocketAddress getRemoteAddress() { return remoteAddress; }
    public void setRemoteAddress(InetSocketAddress remoteAddress) { this.remoteAddress = remoteAddress; }


    public NettyKcp getNettyKcp() {
        return nkcp;
    }

    public void setNettyKcp(NettyKcp nettyKcp) {
        this.nkcp = nettyKcp;
    }

    public boolean isFlushPending() {
        return flushPending;
    }

    public void setFlushPending(boolean flushPending) {
        this.flushPending = flushPending;
    }

    public final class KcpServerChildUnsafe extends AbstractUnsafe {
        @Override
        public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
            safeSetFailure(promise, new UnsupportedOperationException());
        }
        @Override
        protected void flush0() {
            if (isFlushPending()) {
                return;
            }
            super.flush0();
        }
        public void forceFlush() {
            super.flush0();
        }
    }
}
